/*
 * q2map.h
 *
 * Copyright (C) 1999, Ben Swartzlander
 * This file is part of Q2BotCore.
 * For conditions of distribution and use,
 * see the accompanying README file.
 *
 * This is the header file for the functions in
 * q2map.dll
 */

#ifndef __Q2MAP_H
#define __Q2MAP_H

#define Q2MAP_API_VERSION 7

#if defined(__cplusplus)
extern "C"
{
#endif

typedef float vec3_t[3];

/*
 *	PRINTFUNC
 *
 *	A prototype for a function of the form:
 *	void x(char *);
 *	You must pass two such functions to the
 *	qmLoadMap() function;
 */

typedef void (*PRINTFUNC)(char *);

/*
 *	BRUSHLOCATIONFUNC
 *
 *	A prototype for a function of the form:
 *	void x(int,vec3_t *);
 *	Such a function can be used by q2map to find the
 *	location of the moving brushes. See
 *	qmSetBrushLocationFunc.
 */

typedef void (*BRUSHLOCATIONFUNC)(int,vec3_t *);

/*
 *	path_t
 *
 *	A list of vectors up to 513 in length. The length
 *	field tells how many are significant.
 *	This is used by qmFindPath() to return paths
 *	through the map.
 *
 *	NEW: the links array is an list of the links used
 *	internally by the library. If you have a problem
 *	getting to a particular point, you can get the
 *	link number from this array and call
 *	qmMarkLinkInvalid(), then the link will no longer
 *	be used in pathfinding. The mapping from points to
 *	links is: link_num=(point_num-1)/2
 */

typedef struct {
	int length;
	vec3_t points[513];
	int links[256];
} path_t;

/*
 *	qmGetAPIVersion()
 *
 *	This function should have been added earlier. It
 *	just occured to me that it is possible to get one's
 *	DLL's and EXE's mixed up, and if they're not
 *	compatible, gibs will fly. This allows the EXE to
 *	check the version of the DLL before calling any
 *	functions.
 *
 *	Returns: Q2MAP_API_VERSION (#defined above)
 */

int qmGetAPIVersion(void);

/*
 *	qmLoadMap(q2dir,gamedir,mapname,p1,p2)
 *
 *	q2dir: The directory where Quake2 is installed,
 *	       example: "d:/quake2/"
 *	gamedir: An additional directory to search for
 *	         map files in, example: "ctf/"
 *	mapname: The filename of the map, example:
 *	         "maps/q2ctf1.bsp"
 *	p1: function to print normal messages
 *	p2: function to print errors
 *
 *	This function load the specified map for the rest
 *	of these functions to use. If this function is not
 *	called successfully at startup, all other functions
 *	will fail.
 *
 *	Return: true, if map successfully loaded
 *	        false, if there was a problem
 */

bool qmLoadMap(char *,char *,char *,PRINTFUNC,PRINTFUNC);

/*
 *	qmUnloadMap()
 *
 *	This function deallocates all memory associated with
 *	the previously loaded map. After this function is
 *	called, qmLoadMap() may be called again.
 *
 *	NEW: now this function also dumps profiling
 *	information to the screen.
 */

void qmUnloadMap(void);

/*
 *	qmFindPath(start,goal,path,full)
 *
 *	start: a vec3_t to start the search from
 *	goal: the vec3_t to where the path should lead
 *	path: an empty path_t struct
 *	full: a flag that tells the search whether or not
 *	      to fill the path struct
 *
 *	This function does search to create a set of vectors
 *	that form a walkable path from start to goal. It uses
 *	only information from the original .bsp, which is
 *	what makes is so remarkable. The points on the path
 *	usually 24.0 units above the ground, the same height
 *	as the player's origin.
 *	If the full flag is set, the path struct is filled
 *	with the path found. Otherwise it just returns whether
 *	or not a path was found. Not setting the flag can save
 *	significant amounts of CPU, if you have a long list of
 *	points and you just want to know if they are reachable.
 *
 *	BUGS/FEAURES:
 *	The search is limited to 513 nodes, which is not a
 *	serious limitation is practice, because you can find
 *	just about anything on a map with that. I could
 *	recompile with a larger limit, but the memory
 *	requirements are O(n^2) and the CPU requirements are
 *	O(n*log n)
 *	The path returned is not always the shortest, but it's
 *	pretty damn close. This may be fixed in the future, 
 *	but it would require an overhaul of the search queue,
 *	and a performance hit.
 *	Sometimes the path returned is not actually walkable.
 *	It may pass through some small crack or around some
 *	impossible twist. I consider this a major bug, but I
 *	am at a loss for a method to fix it. For now I live
 *	with it, and the bot tries to manually detect when it
 *	is stuck.
 *	Also, the first and last vectors in the path 
 *	(path.points[0] and path.points[path.length-1]) are
 *	not actually needed to complete the path. You can use
 *	them or not. Using them is slower and sometimes more
 *	accurate. I do not use them.
 *	I should note that the goal point is not included in
 *	the path. The goal should be directly walkable from
 *	either of the last two points (and usually the last
 *	point is closer, but not always!)
 *	HINTS:
 *	When following a path, many wierd things can happen
 *	(for outside reasons) I recommend that you consider
 *	a point "visited" when the bot gets within 8-32
 *	units of the point, depending on lag.
 *	Also, sometimes the points are very close together;
 *	so close that you can pass multiple points in one
 *	frame. In this case you should allow for skipping
 *	ahead in the path.
 *	Last piece of advice: my experience is that if your
 *	bot follow this path blindly, lag and prediction can
 *	cause small errors, and your bot may bump into a wall
 *	and possibly get caught (depending on your movement
 *	code) I have a wall avoidance algorithm in place that
 *	seems to prevent the problem, which I may or may not
 *	publish.
 *
 *	Return: true, if a path could be found
 *	        false, if no path was found
 */

bool qmFindPath(vec3_t,vec3_t,path_t *,bool);

/*
 *	qmMarkLinkInvalid(link)
 *
 *	link: the number of the link from the links[]
 *	      array in path_t
 *
 *	If you are following a path, and can't reach
 *	a point, you may want it excluded from future
 *	path searchs. Calling this function on a
 *	link will remove the link from all searches
 *	as long as the map is in memory.
 *	To obtain the link number, look at the formula
 *	in the description of path_t.
 *
 *	NOTE: This function is somewhat of a kludge in
 *	an otherwise fairly elegant API. I hate it too,
 *	but I find this functionality to ABSOLUTELY
 *	NECESSARY for a bot to be competitive.
 */

void qmMarkLinkInvalid(int);

/*
 *	qmTraceLine(start,target,mask)
 *
 *	start: the vec3_t to start the trace
 *	target: the vec3_t to trace to
 *	mask: (new) a mask of contents bits that will
 *	      stop the trace
 *
 *	Traces along the line from start to target
 *	and stops when it hits a part of the map.
 *
 *	NEW: the mask parameter is used to determine
 *	which leaf contents will stop the trace. Until
 *	now, it was always set to 0x00000003. You may
 *	want to allow the trace to pass through some
 *	leaf types, such as water or lava. See below
 *	for the definitions of leaf contents.
 *	If you use 0x00000000 as the mask value, the
 *	return value will always be 1.0. if you use
 *	0x00000003, the function will behave like the
 *	the old version.
 *
 *	Return: the fraction of the distance that could
 *	        be traced without hitting anything,
 *	        between 0.0 and 1.0
 */

float qmTraceLine(vec3_t,vec3_t,int);

/*
 *	The following brush contents are taken from the
 *	official BSP spec, release by id.
 */

#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_WINDOW 2 // translucent, but not watery
#define CONTENTS_AUX 4
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_MIST 64
#define LAST_VISIBLE_CONTENTS 64

// remaining contents are non-visible, and don't eat brushes

#define CONTENTS_AREAPORTAL 0x8000

#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000

// currents can be added to any other contents, and may be mixed
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000

#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity

#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define CONTENTS_LADDER 0x20000000

/*
 *	qmLeafContents(leaf)
 *
 *	leaf: the index of a leaf (from qmGetBSPLeaf)
 *
 *	This function returns the contents field of
 *	a given leaf. See the above definitions for
 *	the meaning of the contents bits.
 *
 *	Return: a bit field
 */

int qmLeafContents(int);

/*
 *	qmGetBSPLeaf(point)
 *
 *	point: a vec3_t
 *
 *	This function returns the index of the leaf
 *	that point is in.
 *
 *	Return: an int greater than or equal to 0
 */

int qmGetBSPLeaf(vec3_t);

/*
 *	qmSetBrushLocationFunc(b)
 *
 *	b: a function to get the location of a moving
 *	brush by number.
 *
 *	(ALPHA) This function is not fully tested. Use
 *	at your own risk.
 *
 *	This function is provided to allow Q2BotCore to
 *	pass moving brush information to q2map, and
 *	thereby increase the accuracy of line tracing.
 *	This function is totally optional, and should
 *	only be used if intersection with moving brushes
 *	is required.
 */

void qmSetBrushLocationFunc(BRUSHLOCATIONFUNC);

#if defined(__cplusplus)
}
#endif 

#endif